package it.unicam.cs.cosy.bioshape.gui;

import hermesV3.BasicServices;
import hermesV3.PlaceAddress;
import hermesV3.agent.Identifier;
import hermesV3.core.id.IdManager;
import hermesV3.core.id.Identify;
import hermesV3.core.id.Trace;
import hermesV3.services.HubService.SimulationAgent;
import hermesV3.util.HermesLogger;
import it.unicam.cs.cosy.bioshape.core.util.Messages;
import hermesV3.util.loggers.LoggingTable;
import it.unicam.cs.cosy.bioshape.gui.visualizer3d.VisualiserDialog;

import javax.swing.AbstractAction;
import javax.swing.AbstractButton;

import java.awt.*;
import java.awt.event.*;
import java.io.File;
import java.io.IOException;

import java.util.ArrayList;
import java.util.Observable;
import java.util.Observer;

import javax.swing.Action;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.JTabbedPane;
import javax.swing.JTable;
import javax.swing.JToolBar;
import javax.swing.JTree;
import javax.swing.SwingConstants;
import javax.swing.SwingUtilities;
import javax.swing.WindowConstants;
import javax.swing.border.EmptyBorder;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableModel;
import javax.swing.table.TableRowSorter;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;

/**
 * GUI for the BioShape simulator.
 * 
 * @author Federico Buti
 */
public class Monitor extends JFrame implements Observer, DocumentListener,
		ChangeListener {

	/** Auto-generated serial ID */
	private static final long serialVersionUID = -4975944156361732135L;

	/** DOCUMENT ME! */
	private DefaultMutableTreeNode topComponentsTree;

	/** DOCUMENT ME! */
	private DefaultMutableTreeNode topAgentsTree;

	/** DOCUMENT ME! */
	private DefaultMutableTreeNode topBornAgentsTree;

	/** DOCUMENT ME! */
	private DefaultTreeModel topAgentTreeModel;

	/** DOCUMENT ME! */
	private DefaultTreeModel topBornAgentsTreeModel;

	/** DOCUMENT ME! */
	private DefaultTreeModel topComponentsTreeModel;

	/** Structure to store the simulator information */
	private JTree componentsTree;

	/** Structure to store all the agents currently on the place */
	private JTree agentsTree;

	/** Structure to store the born agents */
	private JTree bornAgentsTree;

	private JTable agentsTable;

	/** @see Identify */
	private Identify identify;

	/** @see Trace */
	private Trace trace;

	/** @see BasicServices */
	private BasicServices basicServices;

	private ToolAction configureAction;
	private ToolAction exitAction;
	private ToolAction loadAction;
	private ToolAction saveAction;
	private ToolAction newAction;
	private ToolAction saveAsAction;
	private ToolAction simulAction;
	private ToolAction visualAction;
	private ToolAction aboutAction;

	private ClosableTabbedPane masterTabs;

	private JSplitPane split;

	private DashBoard dashboard;

	private Identifier agentsHook;

	private JButton tidy;

	private LoggingTable table;

	private SimulationAgent agentsHookRef;

	private About about;

	private Options options;

	private ToolAction stopAction;

	private ToolAction abstractAction;

	private String hermesHome;

	/**
	 * Creates a new HermesGUI object.
	 * 
	 * @param currentPlaceAddress
	 *            The place address on which the GUI is executed.
	 * @param hermesHome
	 *            Path to the home directory of the HermesV2 platform.
	 * @param basicServices
	 *            The services to work with agents.
	 * @param o
	 *            The {@code IdManager} object of the {@code Place}, which keep
	 *            track of the running agents on the MAS.
	 * @param identify
	 *            Interface to manage {@code Identifier} objects.
	 * @param trace
	 *            Interface to keep track of {@code UserAgent}s on this place.
	 */
	public Monitor(PlaceAddress currentPlaceAddress, String hermesHome,
			BasicServices basicServices, Observable o, Identify identify,
			Trace trace) {
		// icons & title for the title bar
		super("BioShape GUI 0.9a");
		ArrayList<Image> list = new ArrayList<Image>();
		Image im1 = Toolkit.getDefaultToolkit().getImage(
				Monitor.class.getResource("images/icon.png"));
		Image im2 = Toolkit.getDefaultToolkit().getImage(
				Monitor.class.getResource("images/iconBig.png"));
		list.add(im1);
		list.add(im2);
		setIconImages(list);
		setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
		// toolbar
		JToolBar toolBar = new JToolBar("Tools", SwingConstants.HORIZONTAL);
		generateActions();
		addButtons(toolBar);
		toolBar.setFloatable(true);
		toolBar.setRollover(true);

		// menus
		JMenuBar menuBar = new JMenuBar();
		addMenus(menuBar);
		// set closing behaviour
		addWindowListener(new WindowAdapter() {
			@Override
			public void windowClosing(WindowEvent e) {
				if (checkClosing()) {
					Monitor.this.dispose();
					System.exit(0);
				}
			}
		});
		// composing the window
		setJMenuBar(menuBar);
		setLayout(new BorderLayout());
		add(toolBar, BorderLayout.NORTH);
		//
		this.hermesHome = hermesHome;
		o.addObserver(this);
		this.identify = identify;
		this.trace = trace;
		this.basicServices = basicServices;

		this.setLocationRelativeTo(null);
		// Place panel creation...
		topComponentsTree = new DefaultMutableTreeNode("Place address: "
				+ currentPlaceAddress);
		createHermesPlaceNodes();
		topComponentsTreeModel = new DefaultTreeModel(topComponentsTree);
		componentsTree = new JTree(topComponentsTreeModel);
		topAgentsTree = new DefaultMutableTreeNode("Place address: "
				+ currentPlaceAddress);
		createAgentsNodes();
		topAgentTreeModel = new DefaultTreeModel(topAgentsTree);
		agentsTree = new JTree(topAgentTreeModel);
		topBornAgentsTree = new DefaultMutableTreeNode("Place address: "
				+ currentPlaceAddress);
		agentsTable = createUserAgentsTable();
		createBornAgentsNodes();
		topBornAgentsTreeModel = new DefaultTreeModel(topBornAgentsTree);
		bornAgentsTree = new JTree(topBornAgentsTreeModel);
		componentsCreation();
		//
		masterTabs = new ClosableTabbedPane(SwingConstants.TOP,
				JTabbedPane.SCROLL_TAB_LAYOUT);

		masterTabs.addChangeListener(this);
		JTabbedPane tabbedPane = createSystemDataTabs();
		masterTabs.addTab("Simulation Node Data", null, tabbedPane,
				"Information about the current place");
		//
		// addTab(new File(
		// "C:\\Users\\BaCaRoZzo\\Desktop\\test\\BioShapeSchema.xml"));
		split = new JSplitPane(JSplitPane.VERTICAL_SPLIT);
		split.setResizeWeight(1);
		split.setDividerSize(5);

		getContentPane().add(split, BorderLayout.CENTER);
		split.add(masterTabs, JSplitPane.TOP);
		JPanel south = new JPanel();
		south.setLayout(new BorderLayout());
		// south.setPreferredSize(new Dimension(1000, 20));
		south.add(new MemoryMonitor(true), BorderLayout.EAST);
		tidy = new JButton(new ImageIcon(
				Monitor.class.getResource("images/tidy16.png")));
		tidy.setBorder(new EmptyBorder(2, 2, 2, 2));
		tidy.setFocusable(false);
		tidy.setFocusPainted(false);
		tidy.setContentAreaFilled(false);
		tidy.setRolloverEnabled(true);
		tidy.setToolTipText("Click to polish the output table.");
		tidy.setActionCommand("tidy");
		tidy.addActionListener(newAction);
		south.add(tidy, BorderLayout.WEST);
		getContentPane().add(south, BorderLayout.SOUTH);
		//
		// Creation of the simulation agent to communicate with platform agents
		agentsHook = basicServices.getGenesisInterface().createAgent(
				SimulationAgent.class, new Object[] { this });
		Messages.setInput(agentsHook, SimulationAgent.class);
	}

	/**
	 * @return the hermesHome
	 */
	public String getHermesHome() {
		return hermesHome;
	}

	private JTabbedPane createSystemDataTabs() {
		JTabbedPane tabbedPane = new JTabbedPane();
		tabbedPane.addTab("Simultion Node", null, new JScrollPane(
				componentsTree), "Information about the current place");
		tabbedPane.addTab("Born Agents View", null, new JScrollPane(
				bornAgentsTree), "Information about the agents born in the "
				+ "current simulation node");
		JScrollPane sp = new JScrollPane(agentsTree);
		sp.setAutoscrolls(true);
		sp.setMinimumSize(new Dimension(100, 175));
		tabbedPane.addTab("Agents Tree View", null, sp, "Information about "
				+ "the agents running in the current place");
		tabbedPane.addTab("Agents Table View", null, new JScrollPane(
				agentsTable), "Information about the agents running in the "
				+ "current simulation node");
		return tabbedPane;
	}

	/** Generates the menus for the main window */
	private void addMenus(JMenuBar menuBar) {
		// menu File
		JMenu menu = new JMenu("File");
		JMenuItem item = new JMenuItem(newAction);
		menu.add(item);
		item = new JMenuItem(loadAction);
		menu.add(item);
		item = new JMenuItem(saveAction);
		menu.add(item);
		item = new JMenuItem(saveAsAction);
		menu.add(item);
		item = new JMenuItem(configureAction);
		menu.add(item);
		menu.addSeparator();
		item = new JMenuItem(exitAction);
		menu.add(item);
		//
		menuBar.add(menu);
		//
		// menu Actions
		menu = new JMenu("?");
		item = new JMenuItem(aboutAction);
		menu.add(item);
		//
		menuBar.add(menu);

	}

	/**
	 * Updates the {@code JTree} collecting the available {@code ServiceAgent}
	 * and {@code UserAgent} currently running on the {@code Place}.
	 */
	private synchronized void createAgentsNodes() {
		topAgentsTree.removeAllChildren();
		DefaultMutableTreeNode serviceAgentsTree = new DefaultMutableTreeNode(
				"servicesAgents");
		topAgentsTree.add(serviceAgentsTree);
		DefaultMutableTreeNode userAgentsTree = new DefaultMutableTreeNode(
				"userAgents");
		topAgentsTree.add(userAgentsTree);
		for (Identifier agentId : identify.getRunningAgents()) {
			if (agentId != null) {
				DefaultMutableTreeNode agent = new DefaultMutableTreeNode(
						agentId.getName());
				agent.add(new DefaultMutableTreeNode("BornPlace:"
						+ agentId.getBornPlaceAddress()));
				agent.add(new DefaultMutableTreeNode("BornTime:"
						+ agentId.getCreationDate()));
				agent.add(new DefaultMutableTreeNode("SerialId:"
						+ agentId.getSerialId()));
				if (agentId.isServiceAgent()) {
					DefaultMutableTreeNode keyWordsTree = new DefaultMutableTreeNode(
							"DiscoveryKeyWords");
					agent.add(keyWordsTree);
					String[] tempDescription = basicServices
							.getDiscoveryServiceAgentInterface()
							.getServiceDescription(agentId);
					if (tempDescription != null)
						for (String temp : tempDescription)
							keyWordsTree.add(new DefaultMutableTreeNode(temp));
					else
						keyWordsTree.add(new DefaultMutableTreeNode("null"));
					serviceAgentsTree.add(agent);
				} else
					userAgentsTree.add(agent);
			}
		}
		serviceAgentsTree.setUserObject((String) serviceAgentsTree
				.getUserObject()
				+ "("
				+ serviceAgentsTree.getChildCount()
				+ ")");
		userAgentsTree.setUserObject((String) userAgentsTree.getUserObject()
				+ "(" + userAgentsTree.getChildCount() + ")");
	}

	/**
	 * Creates the {@code JTable} with data about the available {@code Agent}
	 * object of the simulation.
	 * 
	 * @return The {@code JTable} with {@code Agent}s information.
	 */
	private JTable createUserAgentsTable() {
		// table model creation and set up
		DefaultTableModel model = new DefaultTableModel() {
			/** Auto-generated serial ID */
			private static final long serialVersionUID = -4120574167165261303L;

			@Override
			public Class<?> getColumnClass(int column) {
				if (column == 1) {
					return Integer.class;
				}
				if (column == 2) {
					return Boolean.class;
				}
				return String.class;
			}
		};
		// columns addition
		model.addColumn("Name");
		model.addColumn("Serial ID");
		model.addColumn("Service Agent");
		model.addColumn("Creation Date");
		model.addColumn("Born Place Address");
		//
		// populating table
		Object[] row = new Object[5];
		for (Identifier agentId : identify.getRunningAgents()) {
			if (agentId != null) {
				row[0] = agentId.getName();
				row[1] = new Integer(agentId.getSerialId());
				row[2] = new Boolean(agentId.isServiceAgent());
				row[3] = agentId.getCreationDate().toString();
				row[4] = agentId.getBornPlaceAddress().toString();
				model.addRow(row);
			}
		}
		// finalising table with sorter
		JTable table = new JTable(model);
		table.setRowSorter(new TableRowSorter<TableModel>(model));
		table.setEnabled(false);
		return table;
	}

	/**
	 * Rebuild the GUI {@code JTree} object collecting statistics about the
	 * Hermes {@code Place} of the current machine.
	 */
	private synchronized void createHermesPlaceNodes() {
		topComponentsTree.removeAllChildren();
		DefaultMutableTreeNode memory = new DefaultMutableTreeNode("Memory");
		DefaultMutableTreeNode memoryFree = new DefaultMutableTreeNode(
				"FreeMemory");
		memoryFree.add(new DefaultMutableTreeNode(Runtime.getRuntime()
				.freeMemory() + ""));
		memory.add(memoryFree);
		DefaultMutableTreeNode maxMemory = new DefaultMutableTreeNode(
				"MaxMemory");
		maxMemory.add(new DefaultMutableTreeNode(Runtime.getRuntime()
				.maxMemory() + ""));
		memory.add(maxMemory);
		DefaultMutableTreeNode totalMemory = new DefaultMutableTreeNode(
				"TotalMemory");
		totalMemory.add(new DefaultMutableTreeNode(Runtime.getRuntime()
				.totalMemory() + ""));
		memory.add(totalMemory);
		DefaultMutableTreeNode threadCount = new DefaultMutableTreeNode(
				"Number of threads");
		threadCount.add(new DefaultMutableTreeNode(new Integer(
				getThreadsCount())));
		topComponentsTree.add(memory);
		topComponentsTree.add(threadCount);
	}

	/**
	 * Calculates the running threads.
	 * 
	 * @return The number of threads
	 */
	private int getThreadsCount() {
		ThreadGroup rootGroup = Thread.currentThread().getThreadGroup();
		ThreadGroup parentGroup;
		while ((parentGroup = rootGroup.getParent()) != null) {
			rootGroup = parentGroup;
		}
		return rootGroup.activeCount();
	}

	/** Updates the list of born {@code Agent} objects of the GUI */
	private synchronized void createBornAgentsNodes() {
		topBornAgentsTree.removeAllChildren();
		DefaultMutableTreeNode agents = new DefaultMutableTreeNode("Agents");
		DefaultMutableTreeNode agent;
		for (String agentId : trace.getBornAgents()) {
			if (agentId != null) {
				agent = new DefaultMutableTreeNode(agentId);
				agent.add(new DefaultMutableTreeNode("CurrentPlaceAddress:"
						+ trace.getCurrentAddress(agentId)));
			} else
				agent = new DefaultMutableTreeNode("null");
			agents.add(agent);
		}
		agents.setUserObject((String) agents.getUserObject() + "("
				+ agents.getChildCount() + ")");
		topBornAgentsTree.add(agents);
	}

	@Override
	public void update(Observable arg0, Object arg1) {
		if (!(arg0 instanceof IdManager))
			return;
		// invoked on the EDT to avoid graphical errors or threading issues
		SwingUtilities.invokeLater(new Runnable() {
			@SuppressWarnings("synthetic-access")
			@Override
			public void run() {
				createHermesPlaceNodes();
				createAgentsNodes();
				createBornAgentsNodes();
				topComponentsTreeModel = new DefaultTreeModel(topComponentsTree);
				topAgentTreeModel = new DefaultTreeModel(topAgentsTree);
				topBornAgentsTreeModel = new DefaultTreeModel(topBornAgentsTree);
				componentsTree.removeAll();
				agentsTree.removeAll();
				bornAgentsTree.removeAll();
				componentsTree.setModel(topComponentsTreeModel);
				agentsTree.setModel(topAgentTreeModel);
				bornAgentsTree.setModel(topBornAgentsTreeModel);
				componentsTree.repaint();
				agentsTree.repaint();
				bornAgentsTree.repaint();
				DefaultTableModel dtm = (DefaultTableModel) agentsTable
						.getModel();
				for (int i = 0; i < dtm.getRowCount(); i++)
					dtm.removeRow(i);
				dtm.setRowCount(0);
				Object row[] = new Object[5];
				for (Identifier agentId : identify
						.getRunningAgents()) {
					if (agentId != null) {
						row[0] = agentId.getName().toString();
						row[1] = new Integer(agentId.getSerialId());
						row[2] = new Boolean(agentId.isServiceAgent());
						row[3] = agentId.getCreationDate().toString();
						row[4] = agentId.getBornPlaceAddress().toString();
						dtm.addRow(row);
					}
				}
				agentsTable.repaint();
			}
		});
	}

	private void generateActions() {
		newAction = new ToolAction("New", new ImageIcon(
				Monitor.class.getResource("images/new24.png")), new ImageIcon(
				Monitor.class.getResource("images/new16.png")),
				"Creates a new simulation XML", "new", new Integer(
						KeyEvent.VK_N));
		loadAction = new ToolAction("Open", new ImageIcon(
				Monitor.class.getResource("images/open24.png")), new ImageIcon(
				Monitor.class.getResource("images/open16.png")),
				"Opens a previously saved simulation XML", "open", new Integer(
						KeyEvent.VK_O));
		saveAction = new ToolAction("Save", new ImageIcon(
				Monitor.class.getResource("images/save24.png")), new ImageIcon(
				Monitor.class.getResource("images/save16.png")),
				"Saves the current selected simulation XML", "save",
				new Integer(KeyEvent.VK_S));
		saveAsAction = new ToolAction("Save as", new ImageIcon(
				Monitor.class.getResource("images/save24.png")), new ImageIcon(
				Monitor.class.getResource("images/save16.png")),
				"Saves the current selected simulation XML", "saveas",
				new Integer(KeyEvent.VK_S));
		simulAction = new ToolAction("Simulate", new ImageIcon(
				Monitor.class.getResource("images/play24.png")), new ImageIcon(
				Monitor.class.getResource("images/play24.png")),
				"Launches (or restarts) the "
						+ "simulation of the current selected XML",
				"simulation", new Integer(KeyEvent.VK_E));
		stopAction = new ToolAction("Stop", new ImageIcon(
				Monitor.class.getResource("images/stop24.png")), new ImageIcon(
				Monitor.class.getResource("images/stop24.png")),
				"Stop the simulation of the current selected XML, if running",
				"stop", new Integer(KeyEvent.VK_Q));
		simulAction.putValue("started", new Boolean(false));
		visualAction = new ToolAction("visualization", new ImageIcon(
				Monitor.class.getResource("images/simu24.png")), null,
				"Visualizes the outcome of a simulation", "visualization",
				new Integer(KeyEvent.VK_R));
		abstractAction = new ToolAction("Abstraction", new ImageIcon(
				Monitor.class.getResource("images/abstract24.png")), null,
				"Generates the abstract derivation of Shape Calculus "
						+ "processes", "abstraction",
				new Integer(KeyEvent.VK_R));
		aboutAction = new ToolAction("About", new ImageIcon(
				Monitor.class.getResource("images/simu24.png")), null,
				"Visualizes the outcome of a simulation", "About", null);
		configureAction = new ToolAction("Configure", new ImageIcon(
				Monitor.class.getResource("images/settings24.png")),
				new ImageIcon(Monitor.class
						.getResource("images/settings16.png")),
				"Set application options", "configure", new Integer(
						KeyEvent.VK_T));
		exitAction = new ToolAction("Exit", new ImageIcon(""), new ImageIcon(
				Monitor.class.getResource("images/exit16.png")),
				"Close application", "exit", new Integer(KeyEvent.VK_X));
	}

	class ToolAction extends AbstractAction {

		/** default serialise value set by eclipse */
		private static final long serialVersionUID = 1L;

		boolean isPainted = false;

		public ToolAction(String text, ImageIcon iconBig, ImageIcon iconSmall,
				String desc, String command, Integer mnemonic) {
			putValue(NAME, text);
			putValue(LARGE_ICON_KEY, iconBig);
			putValue(SMALL_ICON, iconSmall);
			putValue(SHORT_DESCRIPTION, desc);
			putValue(MNEMONIC_KEY, mnemonic);
			putValue(ACTION_COMMAND_KEY, command);
			//
			if (iconBig.getIconHeight() > 0 || iconSmall.getIconHeight() > 0)
				isPainted = true;
			else
				isPainted = false;
		}

		@Override
		public void actionPerformed(ActionEvent e) {
			doOperations(e.getActionCommand());
		}
	}

	void doOperations(String command) {
		if (command.equalsIgnoreCase("new"))
			doNew();
		else if (command.equalsIgnoreCase("open"))
			IOHandler.open(this);
		else if (command.equalsIgnoreCase("save"))
			doSave();
		else if (command.equalsIgnoreCase("saveas"))
			doSaveAs();
		else if (command.equalsIgnoreCase("simulation"))
			doSimulation();
		else if (command.equalsIgnoreCase("stop"))
			doStop();
		else if (command.equalsIgnoreCase("tidy"))
			doTidy();
		else if (command.equalsIgnoreCase("visualization"))
			doVisualisation();
		else if (command.equalsIgnoreCase("configure"))
			configure();
		else if (command.equalsIgnoreCase("about"))
			about.setVisible(true);
		else if (command.equalsIgnoreCase("exit")) {
			if (checkClosing()) {
				dispose();
				System.exit(0);
			}
		}
	}

	private void doStop() {
		DashBoard d = masterTabs.getSelectedComponent();
		if (dashboard != null && dashboard == d) {
			Messages.sendAck(agentsHookRef, agentsHook);
		}
	}

	private void doSaveAs() {
		boolean res = IOHandler.save(masterTabs.getSelectedComponent(), true);
		if (res) {
			saveAction.setEnabled(false);
			masterTabs.setTitleAt(masterTabs.getSelectedIndex(), masterTabs
					.getSelectedComponent().getTitle());
		}
	}

	private void doSimulation() {
		DashBoard d = masterTabs.getSelectedComponent();
		if (d.isDirtyBit())
			doSave();
		if (d.isDirtyBit())
			return;
		// play ---> start/restart simulation
		if (dashboard == null) {
			// if (!d.isStarted() && dashboard == null) {
			dashboard = d;
			// d.setStarted(true);
			simulAction.putValue(Action.LARGE_ICON_KEY, new ImageIcon(
					Monitor.class.getResource("images/pause24.png")));
			simulAction.putValue("started", new Boolean(true));
			Messages.sendSyn(agentsHookRef, agentsHook, d.getFile()
					.getAbsolutePath());
			// pause ---> block simulation
		} else if (((Boolean) simulAction.getValue("started")).booleanValue()) {
			simulAction.putValue("started", new Boolean(false));
			simulAction.putValue(Action.LARGE_ICON_KEY, new ImageIcon(
					Monitor.class.getResource("images/play24.png")));
			Messages.sendSyn(agentsHookRef, agentsHook);
		} else { // restart simulation
			simulAction.putValue("started", new Boolean(true));
			simulAction.putValue(Action.LARGE_ICON_KEY, new ImageIcon(
					Monitor.class.getResource("images/pause24.png")));
			Messages.sendSyn(agentsHookRef, agentsHook);
		}
	}

	private void doVisualisation() {
		try {
			File file = masterTabs.getSelectedComponent().getFile();
			if (file != null && simulationExists(file.getCanonicalPath()))
				new VisualiserDialog(file).setVisible(true);
			else
				HermesLogger.log(HermesLogger.WARNING, getClass()
						.getSimpleName()
						+ " - file must be saved and/or simulated...");
		} catch (IOException e) {
			HermesLogger.log(HermesLogger.WARNING, getClass().getSimpleName()
					+ " - error while reading the simulation data...");
		}
	}

	private boolean simulationExists(String filename) {
		return new File(filename.substring(0, filename.indexOf(".xml"))
				+ ".simu").exists();
	}

	private void doTidy() {
		DefaultTableModel dm = table.getModel();
		dm.getDataVector().removeAllElements();
		((JScrollPane) table.getParent().getParent()).setViewportView(table);
		table.repaint();
	}

	private void doSave() {
		boolean res = IOHandler.save(masterTabs.getSelectedComponent(), false);
		if (res) {
			saveAction.setEnabled(false);
			masterTabs.setTitleAt(masterTabs.getSelectedIndex(), masterTabs
					.getSelectedComponent().getTitle());
		}
	}

	private void doNew() {
		masterTabs.addTab(this);
		DashBoard d = masterTabs.getSelectedComponent();
		d.updateTitle(true);
		d.getCodeEditor().getDocument().addDocumentListener(this);
	}

	private void configure() {
		try {
			options.updateValues();
		} catch (Exception e) {
			HermesLogger.log(HermesLogger.ERROR, this.getClass()
					.getSimpleName()
					+ " - Fatal error while reading the software properties. "
					+ "The simulator will be closed");
		}
		options.setVisible(true);
	}

	/** Generates the buttons for the passed toolbar */
	private void addButtons(JToolBar toolBar) {
		AbstractButton button = null;
		// new action
		button = new JButton(newAction);
		button.setHideActionText(newAction.isPainted);
		button.setFocusable(false);
		toolBar.add(button);
		// open button
		button = new JButton(loadAction);
		button.setHideActionText(loadAction.isPainted);
		button.setFocusable(false);
		toolBar.add(button);
		// save button
		button = new JButton(saveAction);
		button.setHideActionText(saveAction.isPainted);
		button.setFocusable(false);
		toolBar.add(button);
		// separator
		toolBar.addSeparator();
		// simulation button
		button = new JButton(simulAction);
		button.setHideActionText(simulAction.isPainted);
		button.setFocusable(false);
		toolBar.add(button);
		// stop button
		button = new JButton(stopAction);
		button.setHideActionText(stopAction.isPainted);
		button.setFocusable(false);
		toolBar.add(button);
		// separator
		toolBar.addSeparator();
		// visualization button
		button = new JButton(visualAction);
		button.setHideActionText(visualAction.isPainted);
		button.setFocusable(false);
		toolBar.add(button);
		// abstraction button
		button = new JButton(abstractAction);
		button.setHideActionText(abstractAction.isPainted);
		button.setFocusable(false);
		toolBar.add(button);
		// separator
		toolBar.addSeparator();
		// settings button
		button = new JButton(configureAction);
		button.setHideActionText(configureAction.isPainted);
		button.setFocusable(false);
		toolBar.add(button);
	}

	/**
	 * Iterates over the opened tabs and prompt the user about saving each of
	 * them. If the "cancel" button is clicked the operation is stopped and the
	 * closing is not executed.
	 * 
	 * @return {@code true} if all the tab were iterated and they were saved (or
	 *         not) (yes/no buttons were pressed), {@code false} if for a
	 *         certain tab the "cancel" button is pressed
	 */
	boolean checkClosing() {
		// 0 is jumped since it is not a simulation!
		for (int i = 1; i < masterTabs.getTabCount(); i++) {
			masterTabs.setSelectedIndex(i);
			if (!masterTabs.getSelectedComponent().isDirtyBit())
				continue;
			// if the dashboard has the dirtybit set prompt saving...
			String question = "Save simulation " + "\""
					+ masterTabs.getSelectedComponent().getTitle() + "\" ?";
			int retVal = JOptionPane.showConfirmDialog(masterTabs, question,
					"Save", JOptionPane.YES_NO_CANCEL_OPTION);
			// if saving is cancelled for the last tab we do not close the app!
			if (retVal == JOptionPane.CANCEL_OPTION)
				return false;
			if (retVal == JOptionPane.YES_OPTION)
				IOHandler.save(masterTabs.getSelectedComponent(), false);
		}
		// no "cancel" clicked thus we can close the app!
		return true;
	}

	/**
	 * Adds a new simulation tab to the GUI showing the passed simulation file.
	 * 
	 * @param file
	 *            the simulation file as input
	 */
	public void addTab(File file) {
		masterTabs.addTab(file, this);
		DashBoard d = masterTabs.getSelectedComponent();
		d.getCodeEditor().getDocument().addDocumentListener(this);
	}

	/** Helping thread for the creation of support data --> speed up creation */
	@SuppressWarnings("synthetic-access")
	private void componentsCreation() {
		// all the helping components on a different thread...FASTER CREATION!!!
		new Thread() {
			@Override
			public void run() {
				// about frame
				Monitor.this.about = new About(Monitor.this);
				// options frame
				Monitor.this.options = new Options(Monitor.this);
				// handler
				IOHandler.buildHandler();
			}
		}.start();
	}

	@Override
	public void changedUpdate(DocumentEvent e) {
		saveAction.setEnabled(true);
	}

	@Override
	public void insertUpdate(DocumentEvent e) {
		saveAction.setEnabled(true);
	}

	@Override
	public void removeUpdate(DocumentEvent e) {
		saveAction.setEnabled(true);
	}

	@Override
	public void stateChanged(ChangeEvent arg0) {
		saveAsAction.setEnabled(true);
		simulAction.setEnabled(true);
		stopAction.setEnabled(true);
		visualAction.setEnabled(true);
		abstractAction.setEnabled(true);
		DashBoard d = masterTabs.getSelectedComponent();
		if (d != null && d.isDirtyBit())
			saveAction.setEnabled(true);
		else
			saveAction.setEnabled(false);
		if (d == null)
			saveAsAction.setEnabled(false);
		if (d == null || (d != dashboard && dashboard != null)) {
			simulAction.setEnabled(false);
			stopAction.setEnabled(false);
			visualAction.setEnabled(false);
			abstractAction.setEnabled(false);
		}
	}

	/**
	 * Creates the {@code JTable} necessary to show the log in the GUI or hides
	 * the brush icon in the bottom left, if the table is not shown (log is sent
	 * to the standard output).
	 * 
	 * @param table
	 *            The table collecting the logs in the GUI or {@code null}, if
	 *            the logs are sent to the standard output.
	 */
	public void createLogTable(LoggingTable table) {
		JScrollPane scrollPane = new JScrollPane();
		scrollPane.setViewportView(table);
		this.table = table;
		if (table != null) {
			scrollPane.setMinimumSize(new Dimension(100, 175));
			scrollPane.setAutoscrolls(true);
			split.add(scrollPane, JSplitPane.BOTTOM);
		} else
			tidy.setVisible(false);
	}

	/** Ends the current simulation, deallocating data and resetting the GUI. */
	public void simulationEnd() {
		// dashboard.setStarted(false);
		dashboard = null;
		simulAction.putValue(Action.LARGE_ICON_KEY,
				new ImageIcon(Monitor.class.getResource("images/play24.png")));
	}

	/**
	 * Sets the reference to the {@code SimulationAgent}, the Hermes
	 * {@code UserAgent}, used to communicate with the coordinator agents to set
	 * up and run the simulation.
	 * 
	 * @param simulationAgent
	 *            the reference to the{@code SimulationAgent}.
	 */
	public void setAgentref(SimulationAgent simulationAgent) {
		agentsHookRef = simulationAgent;
	}
}